﻿package frEngine.loaders.away3dMd5
{
    import __AS3__.vec.*;
    import baseEngine.utils.*;
    import baseEngine.utils.splitMesh.*;
    import com.gengine.gc.*;
    import flash.geom.*;
    import flash.utils.*;
    import frEngine.core.*;
    import frEngine.loaders.away3dMd5.md5Data.*;
    import frEngine.math.*;

    public class MD5MeshByteArrayParser extends MD5MeshParserBase
    {
        private var _bytes:ByteArray;
        public var hasSplitSurfaceInfo:Boolean;
        public static const isNormal:int = 1;
        public static const isOptimize:int = 2;
        public static const isCompress:int = 3;
        public static const parseTypeValue:int = 8192;
        private static const max:int = 3;
        private static var tempQuat:Quaternion = new Quaternion();
        private static const _tempVector3d:Vector3D = new Vector3D();
        private static const _tempVector3d2:Vector3D = new Vector3D();

        public function MD5MeshByteArrayParser(param1:String)
        {
            super(param1);
            return;
        }// end function

        public function proceedParsing(param1:ByteArray, param2:FrSurface3D, param3:Skeleton) : void
        {
            var _loc_4:Vector.<VertexData> = null;
            var _loc_5:Vector.<uint> = null;
            var _loc_6:Vector.<JointData> = null;
            var _loc_7:uint = 0;
            this._bytes = param1;
            parseHeadAndJoints(this._bytes, param3);
            if (param3.isOptimize)
            {
                parserOptimizeSurface(this._bytes, param2, param3);
            }
            else
            {
                _loc_4 = this.parseMeshVert(param3.hasNormal);
                _loc_5 = this.parseMeshTriangle();
                _loc_6 = this.parseMeshWeight();
                this._bytes = null;
                _loc_7 = param3.numBones;
                translateGeom(_loc_4, _loc_6, _loc_5, param2, maxJointCount);
                param3.maxJointCount = maxJointCount;
                param3.splitSurfaceInfo = SplitMesh.split(param2);
            }
            trace("numBones:" + param3.numBones, "perVertexBones:" + param3.maxJointCount, "surfaceNum:" + param3.splitSurfaceInfo.startIndex.length);
            return;
        }// end function

        private function parseMeshVert(param1:Boolean) : Vector.<VertexData>
        {
            var _loc_4:int = 0;
            var _loc_5:VertexData = null;
            var _loc_2:* = this._bytes.readUnsignedShort();
            var _loc_3:* = new Vector.<VertexData>(_loc_2, true);
            if (param1)
            {
                _loc_4 = 0;
                while (_loc_4 < _loc_2)
                {
                    
                    _loc_5 = new VertexData();
                    _loc_5.index = _loc_4;
                    _loc_5.s = this._bytes.readFloat();
                    _loc_5.t = this._bytes.readFloat();
                    _loc_5.startWeight = this._bytes.readUnsignedShort();
                    _loc_5.countWeight = this._bytes.readUnsignedShort();
                    parseVector3D(this._bytes, _tempVector3d);
                    _loc_5.pos = rotationQuat.rotatePoint(_tempVector3d);
                    parseVector3D(this._bytes, _tempVector3d);
                    _loc_5.normal = rotationQuat.rotatePoint(_tempVector3d);
                    _loc_3[_loc_4] = _loc_5;
                    _loc_4++;
                }
            }
            else
            {
                _loc_4 = 0;
                while (_loc_4 < _loc_2)
                {
                    
                    _loc_5 = new VertexData();
                    _loc_5.index = _loc_4;
                    _loc_5.s = this._bytes.readFloat();
                    _loc_5.t = this._bytes.readFloat();
                    _loc_5.startWeight = this._bytes.readUnsignedShort();
                    _loc_5.countWeight = this._bytes.readUnsignedShort();
                    parseVector3D(this._bytes, _tempVector3d);
                    _loc_5.pos = rotationQuat.rotatePoint(_tempVector3d);
                    _loc_3[_loc_4] = _loc_5;
                    _loc_4++;
                }
            }
            return _loc_3;
        }// end function

        private function parseMeshTriangle() : Vector.<uint>
        {
            var _loc_4:int = 0;
            var _loc_1:* = this._bytes.readUnsignedShort();
            var _loc_2:* = new Vector.<uint>(_loc_1 * 3, true);
            var _loc_3:int = 0;
            while (_loc_3 < _loc_1)
            {
                
                _loc_4 = _loc_3 * 3;
                _loc_2[_loc_4] = this._bytes.readUnsignedShort();
                _loc_2[(_loc_4 + 1)] = this._bytes.readUnsignedShort();
                _loc_2[_loc_4 + 2] = this._bytes.readUnsignedShort();
                _loc_3++;
            }
            return _loc_2;
        }// end function

        private function parseMeshWeight() : Vector.<JointData>
        {
            var _loc_3:int = 0;
            var _loc_4:JointData = null;
            var _loc_1:* = this._bytes.readShort();
            var _loc_2:* = new Vector.<JointData>(_loc_1, true);
            _loc_3 = 0;
            while (_loc_3 < _loc_1)
            {
                
                _loc_4 = new JointData();
                _loc_4.index = _loc_3;
                _loc_4.joint = this._bytes.readShort();
                _loc_4.bias = this._bytes.readFloat();
                if (_loc_4.bias == 0)
                {
                    _loc_4.joint = 0;
                }
                _loc_2[_loc_3] = _loc_4;
                _loc_3++;
            }
            return _loc_2;
        }// end function

        public static function checkMd5Type(param1:uint, param2:uint) : int
        {
            if (param2 >= 256 && param2 < 260)
            {
                param2 = param2 - 256;
            }
            if (param1 == MD5MeshByteArrayParser.parseTypeValue)
            {
                if (param2 == 1)
                {
                    return isNormal;
                }
                if (param2 == 2)
                {
                    return isOptimize;
                }
                return isCompress;
            }
            else
            {
                return isCompress;
            }
        }// end function

        private static function parserOptimizeSurface(param1:ByteArray, param2:FrSurface3D, param3:Skeleton) : void
        {
            var _loc_13:Boolean = false;
            var _loc_14:int = 0;
            var _loc_15:FrVertexBuffer3D = null;
            var _loc_16:int = 0;
            var _loc_17:uint = 0;
            var _loc_18:ByteArray = null;
            var _loc_19:uint = 0;
            var _loc_20:uint = 0;
            var _loc_21:uint = 0;
            var _loc_22:Vector.<int> = null;
            var _loc_4:* = param1.readUnsignedInt();
            var _loc_5:int = 0;
            while (_loc_5 < _loc_4)
            {
                
                _loc_13 = param1.readBoolean();
                _loc_14 = param1.readUnsignedInt();
                _loc_15 = null;
                _loc_16 = 0;
                while (_loc_16 < _loc_14)
                {
                    
                    _loc_19 = param1.readUnsignedInt();
                    _loc_20 = param1.readUnsignedInt();
                    _loc_15 = param2.addVertexData(_loc_19, _loc_20, _loc_13, null);
                    _loc_16++;
                }
                _loc_17 = param1.readUnsignedInt();
                _loc_18 = new GByteArray();
                _loc_18.endian = Endian.LITTLE_ENDIAN;
                param1.readBytes(_loc_18, 0, _loc_17 * 4);
                _loc_15.vertexBytes = _loc_18;
                _loc_5++;
            }
            var _loc_6:* = param1.readUnsignedInt();
            var _loc_7:* = new GByteArray();
            _loc_7.endian = Endian.LITTLE_ENDIAN;
            param1.readBytes(_loc_7, 0, _loc_6 * 2);
            param2.indexBytes = _loc_7;
            var _loc_8:* = new SplitSurfaceInfo();
            var _loc_9:* = param1.readUnsignedInt();
            var _loc_10:* = _loc_8.skinData;
            var _loc_11:* = _loc_8.startIndex;
            var _loc_12:* = _loc_8.triangleNum;
            _loc_5 = 0;
            while (_loc_5 < _loc_9)
            {
                
                _loc_11.push(param1.readUnsignedInt());
                _loc_12.push(param1.readUnsignedInt());
                _loc_21 = param1.readUnsignedInt();
                _loc_22 = new Vector.<int>;
                _loc_10.push(_loc_22);
                _loc_16 = 0;
                while (_loc_16 < _loc_21)
                {
                    
                    _loc_22.push(param1.readUnsignedInt());
                    _loc_16++;
                }
                _loc_5++;
            }
            param3.splitSurfaceInfo = _loc_8;
            return;
        }// end function

        public static function parseHeadAndJoints(param1:ByteArray, param2:Skeleton) : Skeleton
        {
            var _bytes:* = param1;
            var skeleton:* = param2;
            if (_bytes == null)
            {
                return null;
            }
            _bytes.endian = Endian.LITTLE_ENDIAN;
            _bytes.position = 0;
            if (!skeleton)
            {
                skeleton = new Skeleton(null);
            }
            skeleton.magic = _bytes.readUnsignedShort();
            skeleton.version = _bytes.readUnsignedShort();
            if (skeleton.version >= 256 && skeleton.version < 260)
            {
                skeleton.version = skeleton.version - 256;
                skeleton.hasScaledBone = true;
            }
            var type:* = checkMd5Type(skeleton.magic, skeleton.version);
            if (type == isCompress)
            {
                _bytes.position = 0;
                try
                {
                    _bytes.uncompress();
                }
                catch (e:Error)
                {
                    return null;
                }
                skeleton.magic = _bytes.readUnsignedShort();
                skeleton.version = _bytes.readUnsignedShort();
                if (skeleton.version >= 256 && skeleton.version < 260)
                {
                    skeleton.version = skeleton.version - 256;
                    skeleton.hasScaledBone = true;
                }
                type = checkMd5Type(skeleton.magic, skeleton.version);
            }
            skeleton.isOptimize = type == isOptimize;
            if (skeleton.isOptimize)
            {
                parserOptimizeMd5(_bytes, skeleton);
            }
            else
            {
                parserNormalMd5(_bytes, skeleton);
            }
            return skeleton;
        }// end function

        private static function parserOptimizeMd5(param1:ByteArray, param2:Skeleton) : void
        {
            var _loc_6:int = 0;
            var _loc_7:SkeletonJoint = null;
            var _loc_8:Matrix3D = null;
            var _loc_9:Matrix3D = null;
            param2.hasNormal = param1.readBoolean();
            param2.material = param1.readUTF();
            param2.maxJointCount = param1.readUnsignedInt();
            var _loc_3:* = param1.readUnsignedInt();
            var _loc_4:* = param2.inherits;
            var _loc_5:int = 0;
            while (_loc_5 < _loc_3)
            {
                
                _loc_7 = new SkeletonJoint();
                _loc_7.name = param1.readUTF();
                _loc_7.parentIndex = param1.readShort();
                _tempVector3d.x = param1.readFloat();
                _tempVector3d.y = param1.readFloat();
                _tempVector3d.z = param1.readFloat();
                tempQuat.x = param1.readFloat();
                tempQuat.y = param1.readFloat();
                tempQuat.z = param1.readFloat();
                tempQuat.w = param1.readFloat();
                _loc_8 = tempQuat.toMatrix3D();
                _loc_8.appendTranslation(_tempVector3d.x, _tempVector3d.y, _tempVector3d.z);
                _loc_9 = _loc_8.clone();
                _loc_9.invert();
                _loc_9.appendRotation(180, Vector3D.Y_AXIS);
                _loc_7.init(_loc_8, _loc_9);
                _loc_4[_loc_5] = _loc_7;
                _loc_5++;
            }
            _loc_5 = 0;
            while (_loc_5 < _loc_3)
            {
                
                _loc_7 = _loc_4[_loc_5];
                _loc_6 = _loc_7.parentIndex;
                if (_loc_6 != -1)
                {
                    _loc_4[_loc_6].children.push(_loc_7);
                }
                else
                {
                    param2.joinRoot = _loc_7;
                }
                _loc_5++;
            }
            return;
        }// end function

        private static function parserNormalMd5(param1:ByteArray, param2:Skeleton) : void
        {
            var _loc_6:SkeletonJoint = null;
            var _loc_7:Quaternion = null;
            var _loc_8:Matrix3D = null;
            var _loc_11:int = 0;
            var _loc_12:Vector3D = null;
            var _loc_13:Matrix3D = null;
            var _loc_3:* = param1.readBoolean();
            var _loc_4:* = readString(param1);
            var _loc_5:* = param1.readUnsignedShort();
            param2.hasNormal = _loc_3;
            param2.material = _loc_4;
            var _loc_9:* = param2.inherits;
            var _loc_10:int = 0;
            while (_loc_10 < _loc_5)
            {
                
                _loc_6 = new SkeletonJoint();
                _loc_6.name = readString(param1);
                _loc_6.parentIndex = param1.readShort();
                parseVector3D(param1, _tempVector3d);
                _loc_12 = rotationQuat.rotatePoint(_tempVector3d);
                _loc_7 = parseQuaternion(param1);
                _loc_8 = _loc_7.toMatrix3D();
                _loc_8.appendTranslation(_loc_12.x, _loc_12.y, _loc_12.z);
                if (param2.hasScaledBone)
                {
                    parseVector3D(param1, _tempVector3d2);
                }
                _loc_13 = _loc_8.clone();
                _loc_8.invert();
                _loc_13.appendRotation(180, Vector3D.Y_AXIS);
                _loc_6.init(_loc_8, _loc_13);
                _loc_9[_loc_10] = _loc_6;
                _loc_10++;
            }
            _loc_10 = 0;
            while (_loc_10 < _loc_5)
            {
                
                _loc_6 = _loc_9[_loc_10];
                _loc_11 = _loc_6.parentIndex;
                if (_loc_11 != -1)
                {
                    _loc_9[_loc_11].children.push(_loc_6);
                }
                else
                {
                    param2.joinRoot = _loc_6;
                }
                _loc_10++;
            }
            return;
        }// end function

        public static function readString(param1:ByteArray) : String
        {
            var _loc_2:String = null;
            var _loc_6:int = 0;
            var _loc_3:int = 0;
            var _loc_4:* = param1.position;
            var _loc_5:int = 10000;
            while (_loc_3 < _loc_5)
            {
                
                _loc_2 = param1.readMultiByte(1, "gb2312");
                if (_loc_2 == "\\")
                {
                    _loc_6 = param1.position - _loc_4 - 1;
                    param1.position = _loc_4;
                    _loc_2 = param1.readMultiByte(_loc_6, "gb2312");
                    param1.position = param1.position + 2;
                    break;
                }
                _loc_3++;
            }
            if (_loc_3 == _loc_5)
            {
                throw new Error("3dmax输出有误，字符串没有加\\");
            }
            return _loc_2;
        }// end function

        private static function parseVector3D(param1:ByteArray, param2:Vector3D) : void
        {
            param2.x = -param1.readFloat();
            param2.y = param1.readFloat();
            param2.z = param1.readFloat();
            return;
        }// end function

        private static function parseQuaternion(param1:ByteArray) : Quaternion
        {
            var _loc_2:* = new Quaternion();
            _loc_2.x = param1.readFloat();
            _loc_2.y = -param1.readFloat();
            _loc_2.z = -param1.readFloat();
            var _loc_3:* = 1 - _loc_2.x * _loc_2.x - _loc_2.y * _loc_2.y - _loc_2.z * _loc_2.z;
            _loc_2.w = _loc_3 < 0 ? (0) : (-Math.sqrt(_loc_3));
            var _loc_4:* = new Quaternion();
            _loc_4.multiply(rotationQuat, _loc_2);
            return _loc_4;
        }// end function

    }
}
